

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/fluid.png">
  <link rel="icon" href="/img/fluid.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="叶飞">
  <meta name="keywords" content="">
  
    <meta name="description" content="分库分表  1. 为什么要分库分表？ 分表 ​	单表数据量太大，会极大影响你的 sql执行的性能，到了后面你的 sql 可能就跑的很慢了。一般来说，就以我的经验来看，单表到几百万的时候，性能就会相对差一些了，你就得分表了。 ​	分表就是把一个表的数据放到多个表中，然后查询的时候你就查一个表。比如按照用户 id 来分表，将一个用户的数据就放在一个表中。然后操作的时候你对一个用户就操作那个表就好了。">
<meta property="og:type" content="article">
<meta property="og:title" content="MySQL常见面试题-3">
<meta property="og:url" content="http://example.com/2022/04/05/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-3/index.html">
<meta property="og:site_name" content="博客">
<meta property="og:description" content="分库分表  1. 为什么要分库分表？ 分表 ​	单表数据量太大，会极大影响你的 sql执行的性能，到了后面你的 sql 可能就跑的很慢了。一般来说，就以我的经验来看，单表到几百万的时候，性能就会相对差一些了，你就得分表了。 ​	分表就是把一个表的数据放到多个表中，然后查询的时候你就查一个表。比如按照用户 id 来分表，将一个用户的数据就放在一个表中。然后操作的时候你对一个用户就操作那个表就好了。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://example.com/img/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-3.assets/1240.png">
<meta property="og:image" content="http://example.com/img/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-3.assets/1008946.webp">
<meta property="og:image" content="http://example.com/img/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-3.assets/10089464-ab3069913c0f097c.webp">
<meta property="og:image" content="http://example.com/img/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-3.assets/aHR0cHM6Ly91c2VyLWdvbGQtY2RuLnhpdHUuaW8vMjAxOC85LzIxLzE2NWZiNjgzMjIyMDViMmU.jpeg">
<meta property="og:image" content="http://example.com/img/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-3.assets/image-20210822204026552.png">
<meta property="article:published_time" content="2022-04-05T12:01:15.000Z">
<meta property="article:modified_time" content="2022-04-06T11:55:24.506Z">
<meta property="article:author" content="叶飞">
<meta property="article:tag" content="面试">
<meta property="article:tag" content="MySQL">
<meta property="article:tag" content="数据库">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="http://example.com/img/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-3.assets/1240.png">
  
  
  
  <title>MySQL常见面试题-3 - 博客</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/css/highlight-dark.css" />
  




  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"example.com","root":"/","version":"1.9.2","typing":{"enable":true,"typeSpeed":70,"cursorChar":"_","loop":false,"scope":[]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"follow_dnt":true,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
  


  
<meta name="generator" content="Hexo 6.2.0"></head>


<body>
  

  <header>
    

<div class="header-inner" style="height: 70vh;">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>No Tomorrow</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

  

<div id="banner" class="banner" parallax=true
     style="background: url('/img/default.png') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">
    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">
        <div class="h2">
          
            <span id="subtitle" data-typed-text="MySQL常见面试题-3"></span>
          
        </div>

        
          
  <div class="mt-3">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-author" aria-hidden="true"></i>
        叶飞
      </span>
    
    
      <span class="post-meta">
        <i class="iconfont icon-date-fill" aria-hidden="true"></i>
        <time datetime="2022-04-05 20:01" pubdate>
          星期二, 四月 5日 2022, 8:01 晚上
        </time>
      </span>
    
  </div>

  <div class="mt-1">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-chart"></i>
        
          <!-- compatible with older versions-->
          6.1k 字
        
      </span>
    

    
      <span class="post-meta mr-2">
        <i class="iconfont icon-clock-fill"></i>
        
        
        
          <!-- compatible with older versions-->
          51 分钟
        
      </span>
    

    
    
      
        <span id="leancloud-page-views-container" class="post-meta" style="display: none">
          <i class="iconfont icon-eye" aria-hidden="true"></i>
          <span id="leancloud-page-views"></span> 次
        </span>
        
      
    
  </div>


        
      </div>

      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      

    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">MySQL常见面试题-3</h1>
            
            
              <div class="markdown-body">
                
                <h1 id="分库分表"><a class="markdownIt-Anchor" href="#分库分表"></a> 分库分表</h1>
<h2 id="1-为什么要分库分表"><a class="markdownIt-Anchor" href="#1-为什么要分库分表"></a> 1. 为什么要分库分表？</h2>
<p><strong>分表</strong></p>
<p>​	<strong>单表数据量太大</strong>，会极大影响你的 sql执行的性能，到了后面你的 sql 可能就跑的很慢了。一般来说，就以我的经验来看，单表到几百万的时候，性能就会相对差一些了，你就得分表了。</p>
<p>​	分表就是把一个表的数据放到多个表中，然后查询的时候你就查一个表。比如按照用户 id 来分表，将一个用户的数据就放在一个表中。然后操作的时候你对一个用户就操作那个表就好了。这样可以控制每个表的数据量在可控的范围内，比如每个表就固定在 200 万以内。</p>
<p><strong>分库</strong></p>
<p>​	分库就是你一个库一般我们经验而言，最多支撑到并发 2000，一定要扩容了，而且一个健康的单库并发值你最好保持在每秒 1000 左右，不要太大。那么你可以将一个库的数据拆分到多个库中，访问的时候就访问一个库好了。</p>
<p>​	这就是所谓的分库分表。</p>
<p><img src="/img/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-3.assets/1240.png" srcset="/img/loading.gif" lazyload alt="img"></p>
<h2 id="2-用过哪些分库分表中间件不同的分库分表中间件都有什么优点和缺点"><a class="markdownIt-Anchor" href="#2-用过哪些分库分表中间件不同的分库分表中间件都有什么优点和缺点"></a> 2. 用过哪些分库分表中间件？不同的分库分表中间件都有什么优点和缺点？</h2>
<p>​	这个其实就是看看你了解哪些分库分表的中间件，各个中间件的优缺点是啥？然后你用过哪些分库分表的中间件。</p>
<p>比较常见的包括：</p>
<ul>
<li>cobar
<ul>
<li>阿里 b2b 团队开发和开源的，属于 proxy 层方案。早些年还可以用，但是最近几年都没更新了，基本没啥人用，差不多算是被抛弃的状态吧。而且不支持读写分离、存储过程、跨库 join 和分页等操作。</li>
</ul>
</li>
<li>TDDL
<ul>
<li>淘宝团队开发的，属于 client 层方案。支持基本的 crud 语法和读写分离，但不支持 join、多表查询等语法。目前使用的也不多，因为还依赖淘宝的 diamond 配置管理系统。</li>
</ul>
</li>
<li>atlas
<ul>
<li>360 开源的，属于 proxy 层方案，以前是有一些公司在用的，但是确实有一个很大的问题就是社区最新的维护都在 5 年前了。所以，现在用的公司基本也很少了。</li>
</ul>
</li>
<li>⭐️<strong>sharding-jdbc</strong>
<ul>
<li>当当开源的，属于 client 层方案。确实之前用的还比较多一些，因为 SQL 语法支持也比较多，没有太多限制，而且目前推出到了 2.0 版本，支持分库分表、读写分离、分布式 id 生成、柔性事务（最大努力送达型事务、TCC 事务）。而且确实之前使用的公司会比较多一些（这个在官网有登记使用的公司，可以看到从 2017 年一直到现在，是有不少公司在用的），目前社区也还一直在开发和维护，还算是比较活跃，个人认为算是一个现在也<strong>可以选择的方案</strong>。</li>
</ul>
</li>
<li>mycat
<ul>
<li>基于 cobar 改造的，属于 proxy 层方案，支持的功能非常完善，而且目前应该是非常火的而且不断流行的数据库中间件，社区很活跃，也有一些公司开始在用了。但是确实相比于 sharding jdbc 来说，年轻一些，经历的锤炼少一些。</li>
</ul>
</li>
</ul>
<h2 id="3-如何对数据库如何进行垂直拆分或水平拆分的"><a class="markdownIt-Anchor" href="#3-如何对数据库如何进行垂直拆分或水平拆分的"></a> 3. 如何对数据库如何进行垂直拆分或水平拆分的？</h2>
<h3 id="31-水平拆分对数据拆分结构不变"><a class="markdownIt-Anchor" href="#31-水平拆分对数据拆分结构不变"></a> 3.1 水平拆分—对数据拆分，结构不变</h3>
<p>​	<strong>水平拆分</strong>的意思，就是把一个表的数据给弄到多个库的多个表里去，但是每个库的表结构都一样，只不过每个库表放的数据是不同的，所有库表的数据加起来就是全部数据。</p>
<p>​	水平拆分的意义，就是将数据均匀放更多的库里，然后用多个库来抗更高的并发，还有就是用多个库的存储容量来进行扩容。</p>
<p><img src="/img/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-3.assets/1008946.webp" srcset="/img/loading.gif" lazyload alt></p>
<h3 id="32-垂直拆分结构拆分"><a class="markdownIt-Anchor" href="#32-垂直拆分结构拆分"></a> 3.2 垂直拆分—结构拆分</h3>
<p>​	<strong>垂直拆分</strong>的意思，就是<strong>把一个有很多字段的表给拆分成多个表</strong>，<strong>或者是多个库上去</strong>。每个库表的结构都不一样，每个库表都包含部分字段。一般来说，会<strong>将较少的访问频率很高的字段放到一个表里去</strong>，然后<strong>将较多的访问频率很低的字段放到另外一个表里去</strong>。因为数据库是有缓存的，你访问频率高的行字段越少，就可以在缓存里缓存更多的行，性能就越好。这个一般在表层面做的较多一些。</p>
<p><img src="/img/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-3.assets/10089464-ab3069913c0f097c.webp" srcset="/img/loading.gif" lazyload alt="10089464-ab3069913c0f097c"></p>
<h3 id="33-两种分库分表的方式"><a class="markdownIt-Anchor" href="#33-两种分库分表的方式"></a> 3.3 两种<strong>分库分表的方式</strong>：</h3>
<ul>
<li>一种是按照 range 来分，就是<strong>每个库一段连续的数据</strong>，这个一般是按比如<strong>时间范围</strong>来的，但是这种一般较少用，因为很<strong>容易产生热点问题</strong>，大量的流量都打在最新的数据上了。</li>
<li>或者是按照某个字段<strong>hash</strong>一下均匀分散，这个较为常用。</li>
</ul>
<p>range 来分，好处在于说，扩容的时候很简单，因为你只要预备好，给每个月都准备一个库就可以了，到了一个新的月份的时候，自然而然，就会写新的库了；缺点，但是大部分的请求，都是访问最新的数据。实际生产用 range，要看场景。</p>
<p>hash 分发，<strong>好处</strong>在于可以<strong>平均分配</strong>每个库的数据量和请求压力；<strong>坏处</strong>在于说扩容起来比较麻烦，会有一个数据迁移的过程，之前的数据需要<strong>重新计算 hash 值</strong>重新分配到不同的库或表</p>
<h1 id="读写分离-主从同步复制"><a class="markdownIt-Anchor" href="#读写分离-主从同步复制"></a> 读写分离、主从同步（复制）</h1>
<h2 id="1-什么是mysql主从同步"><a class="markdownIt-Anchor" href="#1-什么是mysql主从同步"></a> 1. 什么是MySQL主从同步？</h2>
<p>​	主从同步使得数据可以从一个数据库服务器复制到其他服务器上，在复制数据时，一个服务器充当主服务器（master），其余的服务器充当从服务器（slave）。</p>
<p>​	因为复制是<strong>异步进行</strong>的，所以<code>从服务器</code>不需要一直连接着主服务器，从服务器甚至可以通过拨号断断续续地连接主服务器。通过<strong>配置文件</strong>，可以指定复制所有的数据库，某个数据库，甚至是某个数据库上的某个表。</p>
<h2 id="2-mysql主从同步的目的为什么要做主从同步"><a class="markdownIt-Anchor" href="#2-mysql主从同步的目的为什么要做主从同步"></a> 2. MySQL主从同步的目的？为什么要做主从同步？</h2>
<ol>
<li>
<p>通过增加从服务器来提高数据库的性能，在主服务器上执行写入和更新，在从服务器上向外提供读功能，可以动态地调整从服务器的数量，从而调整整个数据库的性能。</p>
<ul>
<li>读写分离</li>
</ul>
</li>
<li>
<p>提高<strong>数据安全</strong>-因为数据已复制到从服务器，从服务器可以终止复制进程，所以，可以在从服务器上备份而不破坏主服务器相应数据</p>
</li>
<li>
<p>在主服务器上生成实时数据，而在从服务器上分析这些数据，从而提高主服务器的性能</p>
</li>
<li>
<p><strong>数据备份</strong>。一般我们都会做数据备份，可能是写定时任务，一些特殊行业可能还需要手动备份，有些行业要求备份和原数据不能在同一个地方，所以主从就能很好的解决这个问题，不仅备份及时，而且还可以多地备份，保证数据的安全</p>
</li>
</ol>
<h2 id="3-如何实现mysql的读写分离"><a class="markdownIt-Anchor" href="#3-如何实现mysql的读写分离"></a> 3. 如何实现MySQL的读写分离？</h2>
<p>​	其实很简单，就是基于主从复制架构，简单来说，就搞一个主库，挂多个从库，然后我们就单单只是写主库，然后主库会自动把数据给同步到从库上去。</p>
<h2 id="4-mysql主从复制流程和原理"><a class="markdownIt-Anchor" href="#4-mysql主从复制流程和原理"></a> 4. MySQL主从复制流程和原理？</h2>
<p>​		基本原理流程，是3个线程以及之间的关联</p>
<ul>
<li>
<p>主：<strong>binlog线程—</strong>—记录下所有改变了数据库数据的语句，放进master上的binlog中；</p>
</li>
<li>
<p>从：io线程——在使用start slave 之后，负责<strong>从master上拉取 binlog 内容，放进自己的relay log</strong>中；</p>
</li>
<li>
<p>从：sql执行线程——执行relay log中的语句；</p>
</li>
</ul>
<p><strong>复制过程如下</strong>：</p>
<p><img src="/img/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-3.assets/aHR0cHM6Ly91c2VyLWdvbGQtY2RuLnhpdHUuaW8vMjAxOC85LzIxLzE2NWZiNjgzMjIyMDViMmU.jpeg" srcset="/img/loading.gif" lazyload alt="img"></p>
<ul>
<li>
<p>Binary log：主数据库的二进制日志</p>
</li>
<li>
<p>Relay log：从服务器的中继日志</p>
</li>
</ul>
<p>第一步：<strong>master</strong>在每个事务更新数据完成之前，将该操作记录串行地写入到binlog文件中。</p>
<p>第二步：<strong>salve</strong>开启一个I/O Thread，该线程在master打开一个普通连接，主要工作是binlog dump process。如果读取的进度已经跟上了master，就进入睡眠状态并等待master产生新的事件。I/O线程最终的目的是将这些事件写入到中继日志中。</p>
<p>第三步：SQL Thread会读取中继日志，并顺序执行该日志中的SQL事件，从而与主数据库中的数据保持一致。</p>
<h2 id="5-mysql主从同步延时问题如何解决"><a class="markdownIt-Anchor" href="#5-mysql主从同步延时问题如何解决"></a> 5. MySQL主从同步延时问题如何解决？</h2>
<p>​	MySQL 实际上在有两个同步机制，一个是<strong>半同步复制</strong>，用来 <strong>解决主库数据丢失问题</strong>；一个是<strong>并行复制</strong>，用来 解决<strong>主从同步延时</strong>问题。</p>
<ul>
<li>半同步复制，也叫 <strong>semi-sync</strong> 复制，指的就是主库写入 binlog 日志之后，就会将强制此时立即将数据同步到从库，从库将日志写入自己本地的 relay log 之后，接着会返回一个 <strong>ack</strong> 给主库，主库接收到至少一个从库的 ack 之后才会认为写操作完成了。</li>
<li>并行复制，指的是从库开启多个线程，并行读取 relay log 中不同库的日志，然后并行重放不同库的日志，这是库级别的并行。</li>
</ul>
<h1 id="mysql优化"><a class="markdownIt-Anchor" href="#mysql优化"></a> MySQL优化</h1>
<h2 id="1-如何定位及优化sql语句的性能问题"><a class="markdownIt-Anchor" href="#1-如何定位及优化sql语句的性能问题"></a> 1. 如何定位及优化SQL语句的性能问题？</h2>
<p>​	对于低性能的SQL语句的定位，最重要也是最有效的方法就是<strong>使用执行计划</strong>，MySQL提供了<strong>explain</strong>命令来查看语句的执行计划。 我们知道，不管是哪种数据库，或者是哪种数据库引擎，在对一条SQL语句进行执行的过程中都会做很多相关的优化，对于查询语句，最重要的优化方式就是使用索引。</p>
<p>​	而执行计划，就是显示数据库引擎对于SQL语句的执行的详细情况，其中包含了是否使用索引，使用什么索引，使用的索引的相关信息等。<br>
<img src="/img/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-3.assets/image-20210822204026552.png" srcset="/img/loading.gif" lazyload alt="image-20210822204026552"></p>
<h2 id="2-大表数据查询怎么优化"><a class="markdownIt-Anchor" href="#2-大表数据查询怎么优化"></a> 2. 大表数据查询，怎么优化</h2>
<ul>
<li>优化shema、sql语句+索引；</li>
<li>第二<strong>加缓存</strong>，memcached, redis；</li>
<li>主从复制，读写分离；</li>
<li>垂直拆分，根据你模块的耦合度，将一个大的系统分为多个小的系统，也就是分布式系统；</li>
<li>水平切分，针对数据量大的表，这一步最麻烦，最能考验技术水平，要选择一个合理的sharding key, 为了有好的查询效率，表结构也要改动，做一定的冗余，应用也要改，sql中尽量带sharding key，将数据定位到限定的表上去查，而不是扫描全部的表；</li>
</ul>
<h2 id="3-超大分页怎么处理"><a class="markdownIt-Anchor" href="#3-超大分页怎么处理"></a> 3. 超大分页怎么处理?</h2>
<p>​	数据库层面,这也是我们主要集中关注的(虽然收效没那么大),类似于<code>select * from table where age &gt; 20 limit 1000000</code>,10 这种查询其实也是有可以优化的余地的. 这条语句需要 load1000000 数据然后基本上全部丢弃,只取 10 条当然比较慢. 当时我们可以修改为<code>select * from table where id in (select id from table where age &gt; 20 limit 1000000,10)</code>.这样虽然也 load 了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快。</p>
<p>​	解决超大分页,其实主要是靠缓存,可预测性的提前查到内容,缓存至redis等k-V数据库中,直接返回即可.</p>
<p>​	在阿里巴巴《Java开发手册》中,对超大分页的解决办法是类似于上面提到的第一种.</p>
<blockquote>
<p>【推荐】利用延迟关联或者子查询优化超多分页场景。</p>
<p>说明：MySQL并不是跳过offset行，而是取offset+N行，然后返回放弃前offset行，返回N行，那当offset特别大的时候，效率就非常的低下，要么控制返回的总页数，要么对超过特定阈值的页数进行SQL改写。</p>
<p>正例：先快速定位需要获取的id段，然后再关联：</p>
<p>SELECT a.* FROM 表1 a, (select id from 表1 where 条件 LIMIT 100000,20 ) b where <a target="_blank" rel="noopener" href="http://a.id=b.id">a.id=b.id</a></p>
</blockquote>
<h2 id="4-统计过慢查询吗对慢查询都怎么优化过"><a class="markdownIt-Anchor" href="#4-统计过慢查询吗对慢查询都怎么优化过"></a> 4. 统计过慢查询吗？对慢查询都怎么优化过？</h2>
<p>​	在业务系统中，除了使用主键进行的查询，其他的我都会<strong>在测试库上测试其耗时</strong>，慢查询的统计主要由运维在做，会定期将业务中的慢查询反馈给我们。</p>
<p>​	慢查询的优化首先要搞明白慢的原因是什么？ 是查询条件没有命中索引？是load了不需要的数据列？还是数据量太大？</p>
<p>​	所以优化也是针对这三个方向来的，</p>
<ul>
<li>首先分析语句，看看是否load了额外的数据，可能是查询了多余的行并且抛弃掉了，可能是加载了许多结果中并不需要的列，对语句进行分析以及重写。</li>
<li>分析语句的执行计划，然后获得其使用索引的情况，之后修改语句或者修改索引，使得语句可以尽可能的命中索引。</li>
<li>如果对语句的优化已经无法进行，可以考虑表中的数据量是否太大，如果是的话可以进行横向或者纵向的分表。</li>
</ul>
<h2 id="5-如何优化查询过程中的数据访问"><a class="markdownIt-Anchor" href="#5-如何优化查询过程中的数据访问"></a> 5. 如何优化查询过程中的数据访问</h2>
<ul>
<li>访问数据太多导致查询性能下降</li>
<li>确定应用程序是否在检索大量超过需要的数据，可能是太多行或列</li>
<li>确认MySQL服务器是否在分析大量不必要的数据行</li>
<li>查询不需要的数据。
<ul>
<li>解决办法：使用<strong>limit</strong>解决</li>
</ul>
</li>
<li><strong>多表关联</strong>返回全部列。
<ul>
<li>解决办法：指定列名</li>
</ul>
</li>
<li>总是返回全部列。
<ul>
<li>解决办法：**避免使用SELECT ***</li>
</ul>
</li>
<li>重复查询相同的数据。
<ul>
<li>解决办法：可以缓存数据，下次直接读取缓存</li>
</ul>
</li>
<li>是否在扫描<strong>额外的记录</strong>。
<ul>
<li>解决办法：使用explain进行分析，如果发现查询需要扫描大量的数据，但只返回少数的行，可以通过如下技巧去优化：<br>
使用<strong>索引覆盖</strong>扫描，把所有的列都放到索引中，这样存储引擎不需要回表获取对应行就可以返回结果。</li>
</ul>
</li>
<li>改变数据库和表的结构，修改数据表范式</li>
<li>重写SQL语句，让优化器可以以更优的方式执行查询。</li>
</ul>
<h2 id="6-如何优化关联查询"><a class="markdownIt-Anchor" href="#6-如何优化关联查询"></a> 6. 如何优化关联查询</h2>
<ul>
<li>确定<strong>ON</strong>或者<strong>USING</strong>子句中是否有索引。</li>
<li>确保 <strong>GROUP BY</strong> 和 <strong>ORDER BY</strong> 只有<strong>一个表</strong>中的列，这样MySQL才有可能使用索引。</li>
</ul>
<h2 id="7-数据库结构优化"><a class="markdownIt-Anchor" href="#7-数据库结构优化"></a> 7. 数据库结构优化</h2>
<p>​	一个好的数据库设计方案对于数据库的性能往往会起到事半功倍的效果。</p>
<p>​	需要考虑数据冗余、查询和更新的速度、字段的数据类型是否合理等多方面的内容。</p>
<ol>
<li>
<p><strong>将字段很多的表分解成多个表</strong></p>
<p>对于字段较多的表，如果有些字段的使用频率很低，可以将这些字段分离出来形成新表。</p>
</li>
</ol>
<p>因为当一个表的数据量很大时，会由于使用频率低的字段的存在而变慢。</p>
<ol start="2">
<li>
<p><strong>增加中间表</strong></p>
<p>对于需要经常联合查询的表，可以<strong>建立中间表</strong>以提高查询效率。</p>
<p>通过建立中间表，将需要通过联合查询的数据插入到中间表中，然后将原来的联合查询改为对中间表的查询。</p>
</li>
<li>
<p><strong>增加冗余字段</strong></p>
<p>设计数据表时应尽量遵循范式理论的规约，尽可能的减少冗余字段，让数据库设计看起来精致、优雅。</p>
<p>但是，合理的加入冗余字段可以提高查询速度。</p>
<p>表的规范化程度越高，表和表之间的关系越多，需要连接查询的情况也就越多，性能也就越差。</p>
</li>
</ol>
<p>注意：</p>
<p>​	冗余字段的值在一个表中修改了，就要想办法在其他表中更新，否则就会导致数据不一致的问题。</p>
<h2 id="8-mysql数据库cpu飙升到500的话他怎么处理"><a class="markdownIt-Anchor" href="#8-mysql数据库cpu飙升到500的话他怎么处理"></a> 8. MySQL数据库cpu飙升到500%的话他怎么处理？</h2>
<p>​	当 cpu 飙升到 500%时，先用操作系统命令 <strong>top</strong> 命令观察是不是 MySQLd 占用导致的，如果不是，找出占用高的进程，并进行相关处理。</p>
<p>​	如果是 MySQLd 造成的， <strong>show processlist</strong>，看看里面跑的 session 情况，是不是有消耗资源的 sql 在运行。找出消耗高的 sql，看看执行计划是否准确， index 是否缺失，或者实在是数据量太大造成。</p>
<p>​	一般来说，肯定要 kill 掉这些线程(同时观察 cpu 使用率是否下降)，等进行相应的调整(比如说加索引、改 sql、改内存参数)之后，再重新跑这些 SQL。</p>
<p>也有可能是每个 sql 消耗资源并不多，但是突然之间，有大量的 session 连进来导致 cpu 飙升，这种情况就需要跟应用一起来分析为何连接数会激增，再做出相应的调整，比如说限制连接数等。</p>
<h2 id="9-大表怎么优化"><a class="markdownIt-Anchor" href="#9-大表怎么优化"></a> 9. 大表怎么优化？</h2>
<p>​	类似的问题：某个表有近千万数据，CRUD比较慢，如何优化？分库分表了是怎么做的？分表分库了有什么问题？有用到中间件么？他们的原理知道么？</p>
<p>​	当MySQL单表记录数过大时，数据库的CRUD性能会明显下降，一些常见的优化措施如下：</p>
<ul>
<li>限定数据的范围： 务必禁止不带任何限制数据范围条件的查询语句。比如：我们当用户在查询订单历史的时候，我们可以控制在一个月的范围内；</li>
<li><strong>读/写分离</strong>： 经典的数据库拆分方案，<strong>主库负责写，从库负责读；</strong></li>
<li><strong>缓存</strong>： 使用MySQL的缓存，另外对重量级、更新少的数据可以考虑；</li>
<li>通过<strong>分库分表</strong>的方式进行优化，主要有垂直分表和水平分表。</li>
</ul>
<h2 id="参考"><a class="markdownIt-Anchor" href="#参考"></a> 参考</h2>
<h2 id="mysql"><a class="markdownIt-Anchor" href="#mysql"></a> MySQL</h2>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/ThinkWon/article/details/104778621">https://blog.csdn.net/ThinkWon/article/details/104778621</a></p>
<p><a target="_blank" rel="noopener" href="https://haicoder.net/note/mysql-interview/mysql-interview-mysql-binlog.html">https://haicoder.net/note/mysql-interview/mysql-interview-mysql-binlog.html</a></p>
<p><a target="_blank" rel="noopener" href="https://www.modb.pro/db/40241">https://www.modb.pro/db/40241</a></p>
<p><a target="_blank" rel="noopener" href="https://www.jianshu.com/p/05da0fc0950e">https://www.jianshu.com/p/05da0fc0950e</a></p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/ThinkWon/article/details/104778621">https://blog.csdn.net/ThinkWon/article/details/104778621</a></p>

                
              </div>
            
            <hr/>
            <div>
              <div class="post-metas my-3">
  
    <div class="post-meta mr-3 d-flex align-items-center">
      <i class="iconfont icon-category"></i>
      

<span class="category-chains">
  
  
    
      <span class="category-chain">
        
  <a href="/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/" class="category-chain-item">数据库</a>
  
  
    <span>></span>
    
  <a href="/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/" class="category-chain-item">MySQL</a>
  
  

  

      </span>
    
  
</span>

    </div>
  
  
    <div class="post-meta">
      <i class="iconfont icon-tags"></i>
      
        <a href="/tags/%E9%9D%A2%E8%AF%95/">#面试</a>
      
        <a href="/tags/MySQL/">#MySQL</a>
      
        <a href="/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/">#数据库</a>
      
    </div>
  
</div>


              
  

  <div class="license-box my-3">
    <div class="license-title">
      <div>MySQL常见面试题-3</div>
      <div>http://example.com/2022/04/05/20220405-MySQL常见面试题-3/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>叶飞</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2022年4月5日</div>
        </div>
      
      
      <div class="license-meta-item">
        <div>许可协议</div>
        <div>
          
            
            
              <a target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
              <span class="hint--top hint--rounded" aria-label="BY - 署名">
                <i class="iconfont icon-by"></i>
              </span>
              </a>
            
          
        </div>
      </div>
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/04/06/20220406-Mysql%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/" title="Mysql学习笔记">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">Mysql学习笔记</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/04/05/20220405-MySQL%E5%B8%B8%E8%A7%81%E9%9D%A2%E8%AF%95%E9%A2%98-2/" title="MySQL常见面试题-2">
                        <span class="hidden-mobile">MySQL常见面试题-2</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar" style="margin-left: -1rem">
    <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>


    </div>
  </div>
</div>





  



  



  



  



  


  
  









    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v" for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
  </main>

  <footer>
    <div class="footer-inner">
  
    <div class="footer-content">
       <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>Fluid</span></a> 
    </div>
  
  
  
  
</div>

  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>


  <script  src="https://lib.baomitu.com/typed.js/2.0.12/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var subtitle = document.getElementById('subtitle');
      if (!subtitle || !typing) {
        return;
      }
      var text = subtitle.getAttribute('data-typed-text');
      
        typing(text);
      
    })(window, document);
  </script>




  
    <script  src="/js/img-lazyload.js" ></script>
  




  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.18.2/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      headingSelector : CONFIG.toc.headingSelector || 'h1,h2,h3,h4,h5,h6',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      collapseDepth   : CONFIG.toc.collapseDepth || 0,
      scrollSmooth    : true,
      headingsOffset  : -boardTop
    });
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }
  });
</script>


  <script src=https://lib.baomitu.com/clipboard.js/2.0.10/clipboard.min.js></script>

  <script>Fluid.plugins.codeWidget();</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  
      <script>
        if (!window.MathJax) {
          window.MathJax = {
            tex    : {
              inlineMath: { '[+]': [['$', '$']] }
            },
            loader : {
              load: ['ui/lazy']
            },
            options: {
              renderActions: {
                insertedScript: [200, () => {
                  document.querySelectorAll('mjx-container').forEach(node => {
                    let target = node.parentNode;
                    if (target.nodeName.toLowerCase() === 'li') {
                      target.parentNode.classList.add('has-jax');
                    }
                  });
                }, '', false]
              }
            }
          };
        } else {
          MathJax.startup.document.state(0);
          MathJax.texReset();
          MathJax.typeset();
          MathJax.typesetPromise();
        }
      </script>
    

  <script  src="https://lib.baomitu.com/mathjax/3.2.1/es5/tex-mml-chtml.js" ></script>

  <script  src="/js/local-search.js" ></script>

  <script defer src="/js/leancloud.js" ></script>





<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>
<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"log":false,"pluginJsPath":"lib/","pluginModelPath":"assets/","pluginRootPath":"live2dw/","tagMode":false});</script></body>
</html>
